module Lib
    ( cmd
    ) where

import System.Random
import System.IO.Unsafe
import Prelude
import System.Environment
import System.Exit
import Text.Read
import Control.Monad
import Data.Array.IO
import Data.Expr(toNonNegative, NonNegative, ArithmeticOperand, ArithmeticOperator(..), ArithmeticExp, ArithmeticExp(..))
import qualified Addition.Lib as Addition
import qualified Subtraction.Lib as Subtraction


cmd :: IO ()
cmd = do 
    a <- getArgs
    let c = parse a in c

parse :: [String] -> IO ()
parse [] = do 
    outputIO False 10 20
parse ["-h"] = usage >> exit
parse ["-v"] = version >> exit
parse ("-n":n:[])
    | validInt n = do
        outputIO False 10 (read n)
    | otherwise = usage >> exit
parse ("-a":flag:"-n":n:[]) 
    | validBool flag && validInt n = do
        outputIO (read flag) 10 (read n)
    | otherwise = usage >> exit
parse ("-a":flag:"-n":n:s:[]) = do
    if (validBool flag && validInt n && validInt s) 
    then outputIO (read flag) (read s) (read n)
    else usage >> exit 
    return ()
parse _ = usage >> exit 

usage :: IO ()
usage = putStrLn "Usage: children-arithmetic [-vh] [-a True|False] [-n n(n>=0)] s(s>=0)"

version :: IO ()
version = putStrLn "children-arithmetic 0.0.1"

exit :: IO ()
exit = do
    putStrLn "exitSuccess"


validInt :: String -> Bool
validInt strInt
 | (readMaybe strInt :: Maybe Int) == Nothing = False
 | otherwise = True

validBool :: String -> Bool
validBool strBool
 | (readMaybe strBool :: Maybe Bool) == Nothing = False
 | otherwise = True

-- Divides the list in half
divideList :: [a] -> ([a], [a])
divideList ls = splitAt ((length ls) `div` 2) ls

randomInt :: IO Int
randomInt =  randomRIO (1, 10)

randomInt2 :: IO Int
randomInt2 = getStdRandom (randomR (1, 10))

randomizeList :: Eq a => [a] -> [a]
randomizeList ls =
  let lists = (divideList ls) in
    if (length ls) > 1
    then 
        if ((unsafePerformIO randomInt) > 5)
        then (randomizeList (fst lists) ++ randomizeList (snd lists))
        else (randomizeList (snd lists) ++ randomizeList (fst lists))
    else ls

flat :: [(String, String)] -> [String]
flat [] = []
flat (x:tail)= (fst x):(snd x):(flat tail)

shuffle :: [a] -> IO [a]
shuffle xs = do
        ar <- newArray n xs
        forM [1..n] $ \i -> do
            j <- randomRIO (i,n)
            vi <- readArray ar i
            vj <- readArray ar j
            writeArray ar j vi
            return vj
  where
    n = length xs
    newArray :: Int -> [a] -> IO (IOArray Int a)
    newArray n xs =  newListArray (1,n) xs

outputIO :: Bool -> Int -> Int -> IO() --[String]
outputIO flag s n = do
    let additions = randomizeList $ Addition.output flag s
    let subtractions = randomizeList $ Subtraction.output flag s
    let joined = flat $ zip additions subtractions
    let r = take n $ unsafePerformIO $ shuffle joined
    print r
    return ()
